package utils.graph_utils;

import java.util.ArrayList;
import java.util.HashSet;

import utils.math_utils.Coordinate;
import utils.math_utils.MathUtils;

import components.AbstractNeuron;

public class Node {

	private final AbstractNeuron n;
	private ArrayList<Edge> fanOut;
	private ArrayList<Edge> fanIn;
	private Node cameFrom;
	private double distToCameFrom;
	private double distanceTraveled;
	private double heuristicEst;
	private Coordinate coordinates;
	private boolean greedy;
	
	
	public Node(AbstractNeuron n) {
		this.n = n;
		coordinates = n.getCoordinates();
		distToCameFrom = 0;
		distanceTraveled = 0;
		heuristicEst = 0;
		fanOut = new ArrayList<Edge>();
		fanIn = new ArrayList<Edge>();
	}
	
	public ArrayList<Node> expand(HashSet<Node> closedSet){
		ArrayList<Node> nodeList = new ArrayList<Node>();
		Node n;
		for(Edge e : fanOut) {
			
			n = e.getTarg();
			if(!closedSet.contains(n)){
				n.setDistanceTraveled(distanceTraveled + e.getCost());
				n.setCameFrom(this);
				n.setDistToCameFrom(e.getCost());
			}
			nodeList.add(n);
		}
		return nodeList;
	}
	
	private double calcDistanceEst(AbstractNeuron endNode) {
		return MathUtils.euclideanDist(coordinates, endNode.getCoordinates());
	}
	
	public double calcHeuristicEst(AbstractNeuron endNode) {
		if(greedy) 
			heuristicEst = distanceTraveled;
		else
			heuristicEst = calcDistanceEst(endNode) + distanceTraveled;
		
		return heuristicEst;
	}
	
	public void setDistanceTraveled(double distanceTraveled) {
		this.distanceTraveled = distanceTraveled;
	}
	
	public double getDistanceTraveled(){
		return distanceTraveled;
	}
	
	public double getHeuristicEst() {
		return heuristicEst;
	}
	
	public void setHeuristicEst(double heuristicEst) {
		this.heuristicEst = heuristicEst;
	}

	public double getDistToCameFrom() {
		return distToCameFrom;
	}

	public void setDistToCameFrom(double distToCameFrom) {
		this.distToCameFrom = distToCameFrom;
	}

	public Node getCameFrom() {
		return cameFrom;
	}

	public void setCameFrom(Node cameFrom) {
		this.cameFrom = cameFrom;
	}

	public ArrayList<Edge> getFanOut() {
		return fanOut;
	}

	public void setFanOut(ArrayList<Edge> fanOut) {
		this.fanOut = fanOut;
	}

	public Coordinate getCoordinates() {
		return coordinates;
	}

	public void setCoordinates(Coordinate coordinates) {
		this.coordinates = coordinates;
	}

	public AbstractNeuron getN() {
		return n;
	}

	public ArrayList<Edge> getFanIn() {
		return fanIn;
	}

	public void setFanIn(ArrayList<Edge> fanIn) {
		this.fanIn = fanIn;
	}

	public boolean isGreedy() {
		return greedy;
	}

	public void setGreedy(boolean greedy) {
		this.greedy = greedy;
	}


}
